/**
 * Copyright 2013-present NightWorld.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var mongoose = require("mongoose"),
    Schema = mongoose.Schema,
    model = module.exports;

//
// Schemas definitions
//
var OAuthAccessTokensSchema = new Schema({
    accessToken: { type: String },
    clientId: { type: String },
    userId: { type: String },
    expires: { type: Date }
});

var OAuthRefreshTokensSchema = new Schema({
    refreshToken: { type: String },
    clientId: { type: String },
    userId: { type: String },
    expires: { type: Date }
});

var OAuthClientsSchema = new Schema({
    clientId: { type: String },
    clientSecret: { type: String },
    redirectUri: { type: String }
});

var OAuthUsersSchema = new Schema({
    username: { type: String },
    password: { type: String },
    firstname: { type: String },
    lastname: { type: String },
    email: { type: String, default: '' }
});

mongoose.model("OAuthAccessTokens", OAuthAccessTokensSchema);
mongoose.model("OAuthRefreshTokens", OAuthRefreshTokensSchema);
mongoose.model("OAuthClients", OAuthClientsSchema);
mongoose.model("OAuthUsers", OAuthUsersSchema);

var OAuthAccessTokensModel = mongoose.model("OAuthAccessTokens"),
    OAuthRefreshTokensModel = mongoose.model("OAuthRefreshTokens"),
    OAuthClientsModel = mongoose.model("OAuthClients"),
    OAuthUsersModel = mongoose.model("OAuthUsers");

//
// oauth2-server callbacks
//
model.getAccessToken = function (bearerToken, callback) {
    console.log("in getAccessToken (bearerToken: " + bearerToken + ")");

    OAuthAccessTokensModel.findOne({ accessToken: bearerToken }, callback);
};

model.getClient = function (clientId, clientSecret, callback) {
    console.log("in getClient (clientId: " + clientId + ", clientSecret: " + clientSecret + ")");
    if (clientSecret === null) {
        return OAuthClientsModel.findOne({ clientId: clientId }, callback);
    }
    OAuthClientsModel.findOne({ clientId: clientId, clientSecret: clientSecret }, callback);
};

// This will very much depend on your setup, I wouldn"t advise doing anything exactly like this but
// it gives an example of how to use the method to resrict certain grant types
var authorizedClientIds = ["s6BhdRkqt3", "toto"];
model.grantTypeAllowed = function (clientId, grantType, callback) {
    console.log("in grantTypeAllowed (clientId: " + clientId + ", grantType: " + grantType + ")");

    if (grantType === "password") {
        return callback(false, authorizedClientIds.indexOf(clientId) >= 0);
    }

    callback(false, true);
};

model.saveAccessToken = function (token, clientId, expires, userId, callback) {
    console.log("in saveAccessToken (token: " + token + ", clientId: " + clientId + ", userId: " + userId + ", expires: " + expires + ")");

    var accessToken = new OAuthAccessTokensModel({
        accessToken: token,
        clientId: clientId,
        userId: userId,
        expires: expires
    });

    accessToken.save(callback);
};

/*
 * Required to support password grant type
 */
model.getUser = function (username, password, callback) {
    console.log("in getUser (username: " + username + ", password: " + password + ")");

    OAuthUsersModel.findOne({ username: username, password: password }, function(err, user) {
        if(err) return callback(err);
        callback(null, user._id);
    });
};

/*
 * Required to support refreshToken grant type
 */
model.saveRefreshToken = function (token, clientId, expires, userId, callback) {
    console.log("in saveRefreshToken (token: " + token + ", clientId: " + clientId +", userId: " + userId + ", expires: " + expires + ")");

    var refreshToken = new OAuthRefreshTokensModel({
        refreshToken: token,
        clientId: clientId,
        userId: userId,
        expires: expires
    });

    refreshToken.save(callback);
};

model.getRefreshToken = function (refreshToken, callback) {
    console.log("in getRefreshToken (refreshToken: " + refreshToken + ")");

    OAuthRefreshTokensModel.findOne({ refreshToken: refreshToken }, callback);
};
